#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <functional>
#include <string>
#include "err.hpp"

using namespace std;

static void usage(string proc){
    cout << "Usage:\n\t" << proc << "serverip serverport\n"
         << endl;
}

// ./tcp_client serverip serverport
int main(int argc,char* argv[]){

    if(argc!=3){
        cerr << "argc != 3" << endl;
        usage(argv[0]);
        exit(USAGE_ERR);
    }
    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);
    cout << " ↓ client ↓ " << endl;

    //1、创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock<0){
        cerr << "create socket error" << endl;
        exit(SOCKET_ERR);
    }

    //自动给客户端指明IP和Port，绑定
    // 不需要listen，更不需要accept

    //2、明确server，连接服务器
    //创建一个服务器套接字，存放相关信息
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(serverip.c_str());
    server.sin_port = ntohs(serverport);
    //连接
    int cnt = 5;
    while (connect(sock, (struct sockaddr *)&server, sizeof(server)) != 0 && cnt>0){
        cout << "reconnecting..." << cnt-- << endl;
        sleep(1);
    }
    //连接失败
    if(cnt<=0){
        cerr << "connect failed!" << endl;
        exit(CONNECT_ERR);
    }

    //3、连接成功后进行业务处理
    char buf[1024];
    while (1)
    {
        string line;
        cout << "Enter>> ";
        getline(cin, line);

        //向网络文件中写数据
        write(sock, line.c_str(), line.size());

        //从网络文件中读
        ssize_t s = read(sock, buf, sizeof(buf) - 1);
        if(s>0){
            buf[s] = 0;
            cout << "server echo# " << buf << endl;
        }else if(s==0){
            cerr << "server quit!" << endl;
            break;
        }else{
            cerr << "read error: " << strerror(errno) << endl;
            break;
        }
    }

    close(sock);
    return 0;
}